﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Moore;

namespace Moore
{
    class Algorytm
    {
        private int INT_ConstWielkoscPlanszy;
        private const int INT_ConstIloscGraczy = 8;
        Random rand;
        public Algorytm()
        {
            int theSeed = (int)DateTime.Now.Ticks;
            rand = new Random(theSeed);
        }
        /// <summary>
        /// Metoda tworząca plansze z jedzeniem
        /// </summary>
        /// <param name="planszaZJedzeniem">Główna plansza Z jedzeniem.</param>
        public void initPlanszaZJedzeniem(Plansza planszaZJedzeniem)
        {
            INT_ConstWielkoscPlanszy = planszaZJedzeniem.PlanszaArray.Capacity - 1;
            for (int i = 0; i < INT_ConstIloscGraczy; i++)
            {
                int x = rand.Next(0, INT_ConstWielkoscPlanszy);
                int y = rand.Next(0, INT_ConstWielkoscPlanszy);
                planszaZJedzeniem.PlanszaArray[x][y] = 2000;
            }
        }

        /// <summary>
        /// Tworzy graczy
        /// </summary>
        /// <param name="gracze">lista wszystkich graczy</param>
        /// <param name="planszaZGraczami">plansza Z graczami</param>
        public void initGraczy(List<Gracz> gracze, Plansza planszaZGraczami)
        {
            for (int i = 0; i < gracze.Capacity; i++)
            {
                gracze.Add(new Gracz());
                // Polozenie gracza
                gracze[i].X = rand.Next(0, INT_ConstWielkoscPlanszy);
                gracze[i].Y = rand.Next(0, INT_ConstWielkoscPlanszy);
                gracze[i].Nazwa = i + 1;
            }
        }
        public STANY funkcjaPrzejscia(int id, List<Gracz> gracze, Plansza planszaZJedzeniem, TablicaPrzejsc tablica)
        {
            //• K1: mała liczba punktów życia (1 - 4999),
            //• K2: duża liczba punktów życia (5000 - 9999),
            //• K3: maksymalna liczba punktów życia (10000),
            //• K4: wyczerpany zasób punktów życia (0),
            //• K5: nowe informacje,
            //• K6: brak nowych informacji,
            //• K7: odnaleziono miejsce z pożywieniem,
            //• K8: wyczerpanie zasobów pożywienia.
            bool K1 = false, K2 = false, K3 = false, K4 = false, K5 = false, K6 = false, K7 = false, K8 = false;
            if (gracze[id].IloscZyc >= 1 && gracze[id].IloscZyc <= 4999)
            {
                K1 = true;
                tablica.symbol.Add(SymbolWejsciowy.K1);
            }
            if (gracze[id].IloscZyc >= 5000 && gracze[id].IloscZyc <= 9999)
            {
                K2 = true;
                tablica.symbol.Add(SymbolWejsciowy.K2);
            }
            if (gracze[id].IloscZyc >= 10000)
            {
                K3 = true;
                tablica.symbol.Add(SymbolWejsciowy.K3);
            }
            if (gracze[id].IloscZyc <= 0)
            {
                K4 = true;
                tablica.symbol.Add(SymbolWejsciowy.K4);
            }
            if (!CzyNoweInf(id, gracze))
            {
                K5 = true;
                tablica.symbol.Add(SymbolWejsciowy.K5);
            }
            if (planszaZJedzeniem.PlanszaArray[gracze[id].X][gracze[id].Y] <= 0 && gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] > 0)
            {
                K5 = true;
                tablica.symbol.Add(SymbolWejsciowy.K5);
            }
            if (gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] > 0)
            {
                K7 = true;
                tablica.symbol.Add(SymbolWejsciowy.K7);
            }
            if (planszaZJedzeniem.PlanszaArray[gracze[id].X][gracze[id].Y] > 0 && gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] == 0)
            {
                K7 = true;
                tablica.symbol.Add(SymbolWejsciowy.K7);
            }
            if (wyczerpaneJedzenie(planszaZJedzeniem))
            {
                K8 = true;
                tablica.symbol.Add(SymbolWejsciowy.K8);
            }
            //Funkcja przejścia określona następująco 
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K4 && gracze[id].IloscZyc < -200)
            {
                return gracze[id].Stan = STANY.SMIERC;
            }
            if (gracze[id].Stan == STANY.JEDZENIE && K4)
            {
                return gracze[id].Stan = STANY.SMIERC;
            }
            if (gracze[id].Stan == STANY.ROZMOWA && K4)
            {
                return gracze[id].Stan = STANY.SMIERC;
            }
            if (gracze[id].Stan == STANY.PATROL && K5)
            {
                return gracze[id].Stan = STANY.ROZMOWA;
            }
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K5)
            {
                return gracze[id].Stan = STANY.ROZMOWA;
            }
            if (gracze[id].Stan == STANY.PATROL && K1)
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            if (gracze[id].Stan == STANY.ROZMOWA && K1)
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K7)
            {
                return gracze[id].Stan = STANY.JEDZENIE;
            }
            if (gracze[id].Stan == STANY.PATROL && K7)
            {
                return gracze[id].Stan = STANY.JEDZENIE;
            }
            if (gracze[id].Stan == STANY.ROZMOWA && K6)
            {
                return gracze[id].Stan = STANY.PATROL;
            }
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K7)
            {
                return gracze[id].Stan = STANY.JEDZENIE;
            }
            if (gracze[id].Stan == STANY.PATROL && K7 && K3)
            {
                return gracze[id].Stan = STANY.PATROL;
            }
            if (gracze[id].Stan == STANY.PATROL && K3)
            {
                return gracze[id].Stan = STANY.PATROL;
            }
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K1 && K5 && K7)
            {
                return gracze[id].Stan = STANY.SMIERC;
            }
            if (gracze[id].Stan == STANY.POSZUKIWANIE && K4)
            {
                return gracze[id].Stan = STANY.SMIERC;
            }
            if ((gracze[id].Stan == STANY.POSZUKIWANIE && K1) || (gracze[id].Stan == STANY.POSZUKIWANIE && K2))
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            if ((gracze[id].Stan == STANY.JEDZENIE && K3) || (gracze[id].Stan == STANY.JEDZENIE && K2 && K8))
            {
                return gracze[id].Stan = STANY.PATROL;
            }
            if (gracze[id].Stan == STANY.JEDZENIE && K1)
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            if (gracze[id].Stan == STANY.JEDZENIE && K1 && K8)
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            if (gracze[id].Stan == STANY.ROZMOWA && K1 && K8)
            {
                return gracze[id].Stan = STANY.POSZUKIWANIE;
            }
            else
            {
                return STANY.PATROL;
            }
        }

        private bool wyczerpaneJedzenie(Plansza planszaZJedzeniem)
        {
            bool wyczerpane = true;
            foreach (List<int> item in planszaZJedzeniem.PlanszaArray)
            {
                foreach (int jedzenie in item)
                {
                    if (jedzenie > 0)
                    {
                        wyczerpane = false;
                        break;
                    }
                }
            }
            return wyczerpane;
        }

        /// <summary>
        /// Sprawdza czy dane pole jest zajęte przez innego gracza i czy posiadaja taka samą wiedze
        /// </summary>
        /// <param name="id">id gracza który wchodzi na pole</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        /// <returns></returns>
        private static bool CzyNoweInf(int id, List<Gracz> gracze)
        {
            bool takaSamaWiedza = true;
            for (int i = 0; i < gracze.Count(); i++)
                if ((i != id) && (gracze[id].X == gracze[i].X) && (gracze[id].Y == gracze[i].Y))
                    // Sprawdz czy ich wiedza jest rowna
                    for (int j = 0; j < gracze[id].Plansza.PlanszaArray.Count(); j++)
                        for (int k = 0; k < gracze[id].Plansza.PlanszaArray.Count(); k++)
                            if (gracze[id].Plansza.PlanszaArray[j][k] != gracze[i].Plansza.PlanszaArray[j][k])
                            {
                                // Stwierdzam ze wiedza jest nierowna
                                takaSamaWiedza = false;
                                break;
                            }
            return takaSamaWiedza;
        }

        /// <summary>
        /// Spotkanie sie graczy i wymiana informacji
        /// </summary>
        /// <param name="id">id gracza ktory spotyka innych</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        public void rozmowa(int id, List<Gracz> gracze)
        {
            for (int i = 0; i < gracze.Count(); i++)
            {
                if ((id != i) && (gracze[id].X == gracze[i].X) && (gracze[id].Y == gracze[i].Y))
                {
                    // Aktualizuje plansze
                    for (int x = 0; x < gracze[id].Plansza.PlanszaArray.Count(); x++)
                        for (int y = 0; y < gracze[id].Plansza.PlanszaArray.Count(); y++)
                        {
                            // Jesli ma aktualniejsze informacje aktualizuj
                            if (gracze[id].Plansza.PlanszaArray[x][y] < gracze[i].Plansza.PlanszaArray[x][y])
                                gracze[i].Plansza.PlanszaArray[x][y] = gracze[id].Plansza.PlanszaArray[x][y];
                        }
                }
            }
        }

        /// <summary>
        /// Gracz zjada jedzenie na polu na którym stoi
        /// </summary>
        /// <param name="id">id gracza który sie pożywia</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        public void jedzenie(int id, List<Gracz> gracze, Plansza planszaZJedzeniem)
        {
            gracze[id].IloscZyc += 300;
            //dodajemy plansze jesli dopiero została znaleziona
            if (gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] <= 0)
            {
                gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] = planszaZJedzeniem.PlanszaArray[gracze[id].X][gracze[id].Y];
            }
            gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] -= 300;
            planszaZJedzeniem.PlanszaArray[gracze[id].X][gracze[id].Y] -= 300;
            if (gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] <= 0)
            {
                gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] = 0;
                planszaZJedzeniem.PlanszaArray[gracze[id].X][gracze[id].Y] = 0;
            }
        }


        /// <summary>
        /// Idzie w dowolnym kierunku
        /// </summary>
        /// <param name="id">id gracza</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        public void patrol(int id, List<Gracz> gracze)
        {
            switch (rand.Next(0, 3))
            {
                case 0: //lewo
                    if (gracze[id].X - 1 >= 0)
                        gracze[id].X -= 1;
                    break;
                case 1: //prawo
                    if (gracze[id].X + 1 < gracze[id].Plansza.PlanszaArray.Capacity)
                        gracze[id].X += 1;
                    break;
                case 2: //góra
                    if (gracze[id].Y - 1 >= 0)
                        gracze[id].Y -= 1;
                    break;
                case 3: //dół
                    if (gracze[id].Y + 1 < gracze[id].Plansza.PlanszaArray.Capacity)
                        gracze[id].Y += 1;
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// Wybieranie kolejnego pola na ruch
        /// </summary>
        /// <param name="id">id gracza</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        public void poszukiwanie(int id, List<Gracz> gracze)
        {
            if (gracze[id].Plansza.PlanszaArray[gracze[id].X][gracze[id].Y] > 0)
            {

            }
            else
            {
                Dictionary<string, int> kierunekArray = new Dictionary<string, int> { { "lewo", -1 }, { "prawo", -1 }, { "gora", -1 }, { "dol", -1 } };
                // Szukanie na mapie gracza informacji o jedzeniu
                //lewo
                for (int i = gracze[id].X - 1, j = 0; i >= 0; i--, j++)
                {
                    if (gracze[id].Plansza.PlanszaArray[i].Exists(x => x > 0))
                    {
                        kierunekArray["lewo"] = j;
                        break;
                    }
                }
                //prawo
                for (int i = gracze[id].X + 1, j = 0; i < gracze[id].Plansza.PlanszaArray.Capacity; i++, j++)
                {
                    if (gracze[id].Plansza.PlanszaArray[i].Exists(x => x > 0))
                    {
                        kierunekArray["prawo"] = j;
                    }
                }
                //gora
                for (int i = gracze[id].Y - 1, j = 0; i >= 0; i--, j++)
                {
                    if (gracze[id].Plansza.PlanszaArray[gracze[id].X][i] > 0)
                    {
                        kierunekArray["gora"] = j;
                        break;
                    }
                }
                //doł
                for (int i = gracze[id].Y + 1, j = 0; i < gracze[id].Plansza.PlanszaArray.Capacity; i++, j++)
                {
                    if (gracze[id].Plansza.PlanszaArray[gracze[id].X][i] > 0)
                    {
                        kierunekArray["dol"] = j;
                    }
                }
                //jesli jedzenie jest na planszy
                if (kierunekArray.Any(x => x.Value != -1))
                {
                    //usuwanie kierunków bez jedzenia
                    Dictionary<string, int> tmpArray = new Dictionary<string, int>(kierunekArray);
                    foreach (KeyValuePair<string, int> item in tmpArray)
                    {
                        if (item.Value == -1)
                        {
                            kierunekArray.Remove(item.Key);
                        }
                    }
                    var kierunekArrayFindIndex = from k in kierunekArray orderby k.Value ascending select k;

                    switch (kierunekArrayFindIndex.First().Key)
                    {
                        //jesli jedzenie jest na polu obok
                        case "lewo":
                            //lewo
                            if (gracze[id].X - 1 >= 0)
                            {
                                gracze[id].X -= 1;
                            }
                            break;
                        //prawo

                        case "prawo":
                            if (gracze[id].X + 1 < gracze.Capacity)
                            {
                                gracze[id].X += 1;
                            }
                            break;
                        //gora
                        case "gora":
                            if (gracze[id].Y - 1 >= 0)
                            {
                                gracze[id].Y -= 1;
                            }
                            break;
                        //dół
                        case "dol":
                            if (gracze[id].Y + 1 < gracze.Capacity)
                            {
                                gracze[id].Y += 1;
                            }
                            break;
                    }
                }
                // Gdy nie ma informacji o polach z zywnoscia idz gdziekolwiek
                else
                    patrol(id, gracze);
            }
        }

        /// <summary>
        /// Funkcja umierania
        /// </summary>
        /// <param name="id">id gracza</param>
        /// <param name="gracze">lista wszystkich graczy</param>
        public void smierc(int id, List<Gracz> gracze)
        {
            gracze.RemoveAt(id);
        }
    }
}
